#include "ThreadPool.h"
#include <iostream>
#include <string.h>
#include <unistd.h>

//	线程池初始化函数
template<typename T>
ThreadPool<T>::ThreadPool(int min, int max)
{
	
	do {
		// 实例化任务队列
		m_tasks = new TaskQueue<T>;
		if (m_tasks == nullptr)
		{
			std::cout << "new TaskQueue fail" << std::endl;
			break;
		}
		m_thread_ids = new pthread_t[max];
		if (m_thread_ids == nullptr) 
		{
			std::cout << "new pthread_t fail" << std::endl;
			break;
		}

		//	初始化
		memset(m_thread_ids, 0, sizeof(pthread_t) * max);
		m_min_num = min;
		m_max_num = max;
		m_busy_num = 0;
		m_alive_num = min;			//活着的线程应该等于最小的线程数量
		m_exit_num = 0;

		//	初始化锁和条件变量
		if (pthread_mutex_init(&m_mx, NULL) != 0
			|| pthread_cond_init(&m_not_empty, NULL) != 0)
		{
			std::cout << "mutex or condition init fail" << std::endl;
			break;
		}

		shutdown = false;

		//	创建线程
		pthread_create(&m_manager_id, NULL, manager, this);
		for (int i = 0; i < min; i++)
		{
			pthread_create(&m_thread_ids[i], NULL, worker, this);
		}
		//注意需要加return 不然就以为失败跳出循环体释放掉资源了
		return;
	} while (0);		//使用do while(0)的原因是因为后面需要用以释放内存资源

	//初始化步骤失败，释放资源
	if (m_thread_ids)	delete[] m_thread_ids;
	if (m_tasks)		delete m_tasks;
}

//	工作函数
template<typename T>
void* ThreadPool<T>::worker(void* arg) {
	ThreadPool* pool = static_cast<ThreadPool*>(arg);

	while (true)
	{
		pthread_mutex_lock(&pool->m_mx);				//	上锁

		//	当前任务队列是否为空
		while (pool->m_tasks->get_task_number() == 0 && !pool->shutdown)
		{
			//	为空就阻塞工作线程
			pthread_cond_wait(&pool->m_not_empty, &pool->m_mx);

			//判断是不是要销毁线程
			if (pool->m_exit_num > 0)
			{
				pool->m_exit_num--;
				if (pool->m_alive_num > pool->m_min_num)
				{
					pool->m_alive_num--;
					pthread_mutex_unlock(&pool->m_mx);	//	记得解锁
					pool->thread_exit();
				}
			}
		}

		//	判断线程池是否被关闭了
		if (pool->shutdown)
		{
			pthread_mutex_unlock(&pool->m_mx);		//	解锁
			pool->thread_exit();					//	销毁线程
		}

		//	从任务队列中取出一个任务
		Task<T> task = pool->m_tasks->take_task();
		pool->m_busy_num++;
		pthread_mutex_unlock(&pool->m_mx);			//	解锁

		std::cout << "thread " << std::to_string(pthread_self()) << "start working..." << std::endl;

		//	执行任务
		task.funtion(task.arg);
		delete task.arg;
		task.arg = NULL;

		std::cout << "thread " << std::to_string(pthread_self()) << "end working..." << std::endl;
		pthread_mutex_lock(&pool->m_mx);
		pool->m_busy_num--;
		pthread_mutex_unlock(&pool->m_mx);
	}

	return NULL;
}

//	管理者线程工作函数
template<typename T>
void* ThreadPool<T>::manager(void* arg) {
	ThreadPool* pool = static_cast<ThreadPool*>(arg);
	while (!pool->shutdown)
	{
		//	每隔三秒检测一次
		sleep(3);

		//	取出线程池中任务的数量、当前工作的线程数量和正在忙的线程个数
		pthread_mutex_lock(&pool->m_mx);
		int queue_size = pool->m_tasks->get_task_number();
		int live_num = pool->m_alive_num;
		int busy_num = pool->m_busy_num;
		pthread_mutex_unlock(&pool->m_mx);

		//	添加线程	根据实际的业务要求来制定
		//	规则：任务的个数>存活的线程的个数 && 存活的线程数<最大线程数
		if (queue_size > live_num && live_num < pool->m_max_num)
		{
			pthread_mutex_lock(&pool->m_mx);			//	使用线程池元素时记得加锁
			int count = 0;
			//	遍历线程id组找出没有使用的线程id来创建线程
			for (int i = 0; i < pool->m_max_num && count < NUMBER
				&& pool->m_alive_num < pool->m_max_num; i++)
			{
				if (pool->m_thread_ids[i] == 0)
				{
					pthread_create(&pool->m_thread_ids[i], NULL, worker, pool);
					count++;
					pool->m_alive_num++;
				}
			}
			pthread_mutex_unlock(&pool->m_mx);
		}

		//	销毁线程	根据实际的业务要求来制定规则
		//	规则：正在工作的线程 * 2 < 存活的线程数	&& 存活的线程 > 最小线程数
		if (busy_num * 2 < live_num && live_num > pool->m_min_num)
		{
			pthread_mutex_lock(&pool->m_mx);
			pool->m_exit_num = NUMBER;
			pthread_mutex_unlock(&pool->m_mx);

			//	让工作线程自杀
			for (int i = 0; i < NUMBER; i++)
			{
				pthread_cond_signal(&pool->m_not_empty);		//	唤醒线程
			}
		}
	}
	return NULL;
}

//	线程退出函数
template<typename T>
void ThreadPool<T>::thread_exit() {
	//获取当前线程id
	pthread_t tid = pthread_self();
	for (int i = 0; i < m_max_num; i++)
	{
		if (m_thread_ids[i] == tid)
		{
			m_thread_ids[i] = 0;
			std::cout << "thread " << std::to_string(pthread_self()) << " exiting..." << std::endl;
			break;
		}
	}
	pthread_exit(NULL);
}

//	给线程池添加任务
template<typename T>
void ThreadPool<T>::add_task(Task<T> task)
{
	//判断线程池是否被销毁
	if (shutdown)
		return;

	//	添加任务
	//因为在TaskQueue实例中，对添加任务的操作已经做了加锁解锁操作，所以这里不用做
	m_tasks->add_task(task);

	//	唤醒阻塞线程来完成任务
	pthread_cond_signal(&m_not_empty);
}

//	获取线程池中工作的线程的个数
template<typename T>
int ThreadPool<T>::get_busy_num() {
	pthread_mutex_lock(&m_mx);
	int res = m_busy_num;
	pthread_mutex_unlock(&m_mx);
	return res;
}

//	获取线程池中存活的线程个数
template<typename T>
int ThreadPool<T>::get_alive_num() {
	pthread_mutex_lock(&m_mx);
	int res = m_alive_num;
	pthread_mutex_unlock(&m_mx);
	return res;
}

//	销毁线程池
template<typename T>
ThreadPool<T>::~ThreadPool()
{
	//	关闭线程池
	shutdown = true;

	//	阻塞回收管理者线程
	pthread_join(m_manager_id, NULL);

	//	唤醒阻塞消费者线程
	for (int i = 0; i < m_alive_num; i++) {
		pthread_cond_signal(&m_not_empty);
	}

	//	释放堆内存
	if (m_tasks)		delete m_tasks;
	if (m_thread_ids)	delete[] m_thread_ids;

	pthread_mutex_destroy(&m_mx);
	pthread_cond_destroy(&m_not_empty);
}